package cn.codeartist.springboot.component.http.proxy.impl;

import cn.codeartist.springboot.component.http.bean.TypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;

/**
 * 默认代理实现
 *
 * @author 艾江南
 * @date 2019/3/22
 */
public class DefaultHttpProxy extends AbstractHttpProxy {

    private static final MediaType DEFAULT_FORM_DATA_MEDIA_TYPE = new MediaType(MediaType.APPLICATION_FORM_URLENCODED, DEFAULT_CHARSET);

    // GET

    @Override
    public <T> T get(String uri, Class<T> responseType, Object... uriVariables) {
        return executeGet(uri, null, responseType, uriVariables);
    }

    @Override
    public <T> T get(String uri, TypeReference<T> responseType, Object... uriVariables) {
        return executeGet(uri, null, responseType, uriVariables);
    }

    @Override
    public <T, P> T get(String uri, P request, Class<T> responseType, Object... uriVariables) {
        return executeGet(uri, request, responseType, uriVariables);
    }

    @Override
    public <T, P> T get(String uri, P request, TypeReference<T> responseType, Object... uriVariables) {
        return executeGet(uri, request, responseType, uriVariables);
    }

    // POST

    @Override
    public <T> T post(String uri, Class<T> responseType, Object... uriVariables) {
        return executePost(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, null, responseType, uriVariables);
    }

    @Override
    public <T> T post(String uri, TypeReference<T> responseType, Object... uriVariables) {
        return executePost(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, null, responseType, uriVariables);
    }

    @Override
    public <T, P> T post(String uri, P request, Class<T> responseType, Object... uriVariables) {
        return executePost(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, request, responseType, uriVariables);
    }

    @Override
    public <T, P> T post(String uri, P request, TypeReference<T> responseType, Object... uriVariables) {
        return executePost(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, request, responseType, uriVariables);
    }

    @Override
    public <T, P> T postJson(String uri, P requestBody, Class<T> responseType, Object... uriVariables) {
        return executePost(uri, MediaType.APPLICATION_JSON_UTF8, requestBody, responseType, uriVariables);
    }

    @Override
    public <T, P> T postJson(String uri, P requestBody, TypeReference<T> responseType, Object... uriVariables) {
        return executePost(uri, MediaType.APPLICATION_JSON_UTF8, requestBody, responseType, uriVariables);
    }

    // PUT

    @Override
    public <T> T put(String uri, Class<T> responseType, Object... uriVariables) {
        return executePut(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, null, responseType, uriVariables);
    }

    @Override
    public <T> T put(String uri, TypeReference<T> responseType, Object... uriVariables) {
        return executePut(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, null, responseType, uriVariables);
    }

    @Override
    public <T, P> T put(String uri, P request, Class<T> responseType, Object... uriVariables) {
        return executePut(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, request, responseType, uriVariables);
    }

    @Override
    public <T, P> T put(String uri, P request, TypeReference<T> responseType, Object... uriVariables) {
        return executePut(uri, DEFAULT_FORM_DATA_MEDIA_TYPE, request, responseType, uriVariables);
    }

    @Override
    public <T, P> T putJson(String uri, P requestBody, Class<T> responseType, Object... uriVariables) {
        return executePut(uri, MediaType.APPLICATION_JSON_UTF8, requestBody, responseType, uriVariables);
    }

    @Override
    public <T, P> T putJson(String uri, P requestBody, TypeReference<T> responseType, Object... uriVariables) {
        return executePut(uri, MediaType.APPLICATION_JSON_UTF8, requestBody, responseType, uriVariables);
    }

    // DELETE

    @Override
    public <T> T delete(String uri, Class<T> responseType, Object... uriVariables) {
        return executeDelete(uri, null, responseType, uriVariables);
    }

    @Override
    public <T> T delete(String uri, TypeReference<T> responseType, Object... uriVariables) {
        return executeDelete(uri, null, responseType, uriVariables);
    }

    @Override
    public <T, P> T delete(String uri, P request, Class<T> responseType, Object... uriVariables) {
        return executeDelete(uri, request, responseType, uriVariables);
    }

    @Override
    public <T, P> T delete(String uri, P request, TypeReference<T> responseType, Object... uriVariables) {
        return executeDelete(uri, request, responseType, uriVariables);
    }

    private <T, P> T executeGet(String uri, P request, Class<T> responseType, Object... uriVariables) {
        uri = queryTemplateHandler(uri, request);
        return super.execute(HttpMethod.GET, uri, null, null, responseType, uriVariables);
    }

    private <T, P> T executeGet(String uri, P request, TypeReference<T> responseType, Object... uriVariables) {
        uri = queryTemplateHandler(uri, request);
        return super.execute(HttpMethod.GET, uri, null, null, responseType, uriVariables);
    }

    private <T, P> T executeDelete(String uri, P request, Class<T> responseType, Object... uriVariables) {
        uri = queryTemplateHandler(uri, request);
        return super.execute(HttpMethod.DELETE, uri, null, null, responseType, uriVariables);
    }

    private <T, P> T executeDelete(String uri, P request, TypeReference<T> responseType, Object... uriVariables) {
        uri = queryTemplateHandler(uri, request);
        return super.execute(HttpMethod.DELETE, uri, null, null, responseType, uriVariables);
    }

    private <T, P> T executePost(String uri, MediaType mediaType, P body, Class<T> responseType, Object... uriVariables) {
        return super.execute(HttpMethod.POST, uri, mediaType, body, responseType, uriVariables);
    }

    private <T, P> T executePost(String uri, MediaType mediaType, P body, TypeReference<T> responseType, Object... uriVariables) {
        return super.execute(HttpMethod.POST, uri, mediaType, body, responseType, uriVariables);
    }

    private <T, P> T executePut(String uri, MediaType mediaType, P body, Class<T> responseType, Object... uriVariables) {
        return super.execute(HttpMethod.PUT, uri, mediaType, body, responseType, uriVariables);
    }

    private <T, P> T executePut(String uri, MediaType mediaType, P body, TypeReference<T> responseType, Object... uriVariables) {
        return super.execute(HttpMethod.PUT, uri, mediaType, body, responseType, uriVariables);
    }
}
